﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.IO;
using System.Windows.Threading;
using Microsoft.Win32;
using System.Diagnostics;

namespace Light_Calendar
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private DetailCell detailCell;
        private DetailCell reminderCell;
        private EditWindow editWindow;
        private Options optionsWindow;
        private NotifyIcon notifyIcon;
        private HotkeyEx hotkey;
        private UIElement toFocus;
        private DateTime currentDate;
        private DispatcherTimer timer;

        public DateTime FocusedDate { get; set; }
        public bool IsEditing { get; set; }
        public bool IsDeleting { get; set; }
        public bool InOptions { get; set; }
        public EventsData Data { get; set; }
        public CalendarCache Cache { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            detailCell = new DetailCell();
            detailCell.Margin = new Thickness(1, 2, 0, 1);
            detail.Children.Add(detailCell);
            reminderCell = new DetailCell();
            reminderCell.Margin = new Thickness(1, 2, 1, 1);
            detail.Children.Add(reminderCell);

            IsEditing = false;
            IsDeleting = false;
            InOptions = false;

            string dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\Light Calendar";
            new DirectoryInfo(dir).Create();
            FileInfo fi = new FileInfo(dir + @"\Calendar.xml");
            if (fi.Exists) fi.CopyTo(fi.FullName + ".bak", true);
            Data = new EventsData(fi.FullName);
            Data.Updated += new EventsData.UpdateEventHandler(Data_Updated);
            Cache = new CalendarCache(Data);

            MoveCalendar(DateTime.Today, true);
            FocusDate(DateTime.Today);

            ContextMenuStrip notifyIconMenu = new ContextMenuStrip();
            ToolStripMenuItem menuItemOpen = new ToolStripMenuItem("Open", null, delegate { Activate(); });
            menuItemOpen.Font = new System.Drawing.Font(menuItemOpen.Font, System.Drawing.FontStyle.Bold);
            notifyIconMenu.Items.Add(menuItemOpen);
            notifyIconMenu.Items.Add("Exit", null, delegate { Shutdown(); });
            notifyIconMenu.ShowImageMargin = false;

            notifyIcon = new NotifyIcon();
            notifyIcon.Text = "Light Calendar";
            notifyIcon.Icon = Properties.Resources.Calendar;
            notifyIcon.ContextMenuStrip = notifyIconMenu;
            notifyIcon.MouseClick += delegate(object sender, System.Windows.Forms.MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left) { Activate(); }
                if (e.Button == MouseButtons.Right) notifyIcon.ContextMenuStrip.Show();
            };
            notifyIcon.MouseDoubleClick += delegate { Activate(); };

            currentDate = DateTime.Today;
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += new EventHandler(timer_Tick);

            Left = Properties.Settings.Default.left;
            Top = Properties.Settings.Default.top;
        }

        void timer_Tick(object sender, EventArgs e)
        {
            if (currentDate != DateTime.Today)
            {
                currentDate = DateTime.Today;
                FocusDate(DateTime.Today, false);
                UpdateReminder();
            }
        }

        void Data_Updated(CalendarEvent e)
        {
            foreach (CalendarCell c in calendarCells.Children)
                if (!Cache.IsCached(c.Date)) c.Events = Cache.EventsOn(c.Date);

            if (e == null || e.Date == FocusedDate) UpdateDetail(FocusedDate);

            if (!Cache.IsReminderCached) UpdateReminder();

            if (e != null && IsLoaded)
                foreach (EventBlock b in FocusDate(e.Date, false).eventsList.Children)
                    if (b.Event.Id == e.Id)
                    {
                        toFocus = b;
                        b.BorderBrush = Brushes.Gray;
                    }
        }

        private void MoveCalendar(DateTime date, bool focusOnFirstRow)
        {
            int dayOffset = (int)(date.DayOfWeek);
            if (!focusOnFirstRow) dayOffset += 7;

            calendarCells.Children.Clear();
            for (int i = 0; i < 14; i++)
            {
                CalendarCell c = new CalendarCell();
                c.Date = date.AddDays(i - dayOffset);
                c.MouseDown += new MouseButtonEventHandler(cell_MouseDown);
                c.Events = Cache.EventsOn(c.Date);
                calendarCells.Children.Add(c);
            }
        }

        public CalendarCell FocusDate(DateTime date)
        {
            return FocusDate(date, true);
        }

        public CalendarCell FocusDate(DateTime date, bool keyboardFocus)
        {
            if (date == FocusedDate)
                foreach (CalendarCell c in calendarCells.Children) if (date == c.Date) return c;
            CalendarCell r = null;
            dateText.Text = date.ToString("MMMM, yyyy");
            if (date < ((CalendarCell)calendarCells.Children[0]).Date) MoveCalendar(date, true);
            else if (date > ((CalendarCell)calendarCells.Children[13]).Date) MoveCalendar(date, false);
            foreach (CalendarCell c in calendarCells.Children)
            {
                if (date == c.Date)
                {
                    c.cellBorder.BorderBrush = Brushes.LightSteelBlue;
                    r = c;
                }
                else if (FocusedDate == c.Date) c.cellBorder.BorderBrush = Brushes.Transparent;
            }
            FocusedDate = date;
            if (keyboardFocus) calendarCells.Focus();
            UpdateDetail(date);
            return r;
        }

        private void UpdateDetail(DateTime date)
        {
            detailCell.caption.Text = date.ToString("dddd, MMMM d, yyyy");
            if (date == DateTime.Today) detailCell.caption.Text += " (Today)";
            detailCell.eventsList.Children.Clear();
            foreach (CalendarEvent e in Cache.EventsOn(date))
                detailCell.eventsList.Children.Add(new EventBlock(date, e, true));
        }

        private void UpdateReminder()
        {
            reminderCell.eventsList.Children.Clear();
            for (int i = 0; i <= 30; i++)
            {
                DateTime d = DateTime.Today.AddDays(i);
                foreach (CalendarEvent e in Cache.EventsOn(d))
                    if (e.Reminder >= i)
                    {
                        EventBlock b = new EventBlock(d, e, true);
                        b.description.Text = d.ToString("ddd M/d: ") + b.description.Text;
                        reminderCell.eventsList.Children.Add(b);
                    }
            }
            Cache.IsReminderCached = true;
        }

        private void cell_MouseDown(object sender, MouseButtonEventArgs e)
        {
            FocusDate(((CalendarCell)sender).Date);
            if (e.ClickCount == 2 && !IsEditing) New(((CalendarCell)sender).Date);
            e.Handled = true;
        }

        public void New(DateTime date)
        {
            CalendarEvent calendarEvent = new CalendarEvent(date);
            Data.Add(calendarEvent);
            Edit(calendarEvent);
        }

        public void Edit(CalendarEvent calendarEvent)
        {
            IsEditing = true;
            editWindow = new EditWindow(calendarEvent);
            editWindow.Top = Top + 320;
            editWindow.Left = Left + 400;
            editWindow.Show();
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            Hide();
            notifyIcon.Visible = true;
            RegisterHotkey();
            reminderCell.caption.Text = "Events Reminder";
            UpdateReminder();
            timer.Start();
        }

        public void RegisterHotkey()
        {
            if (hotkey != null) hotkey.Dispose();
            hotkey = new HotkeyEx(Properties.Settings.Default.hotkey);
            hotkey.HotkeyPressed += delegate { Activate(); };
            try
            {
                hotkey.Enabled = true;
            }
            catch (ManagedWinapi.HotkeyAlreadyInUseException)
            {
                notifyIcon.BalloonTipTitle = "Light Calendar (Error)";
                notifyIcon.BalloonTipText = "Hotkey is already in use. Click here to change hotkey.";
                notifyIcon.BalloonTipClicked += delegate { Activate(); ShowOptions(); };
                notifyIcon.ShowBalloonTip(0);
            }
        }

        public void RegisterAutostart()
        {
            RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"Software\Light Calendar\", false);
            string filename = (string)regKey.GetValue("Location") + "Light Calendar.exe";
            regKey.Close();
            regKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run\", true);
            if (Properties.Settings.Default.autostart)
                regKey.SetValue("Light Calendar", filename);
            else
                if (regKey.GetValue("Light Calendar") != null) regKey.DeleteValue("Light Calendar");
            regKey.Close();
        }

        private void MainWindow_Deactivated(object sender, EventArgs e)
        {
            if (Properties.Settings.Default.autohide &&
                IsVisible && !IsEditing && !IsDeleting && !InOptions) Hide();
        }

        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = true;
        }

        private void Shutdown()
        {
            Properties.Settings.Default.left = Left;
            Properties.Settings.Default.top = Top;
            Properties.Settings.Default.Save();
            timer.Stop();
            hotkey.Dispose();
            notifyIcon.Dispose();
            App.Current.Shutdown();
        }

        private void calendarCells_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.PageUp: FocusDate(FocusedDate.AddDays(-14)); break;
                case Key.PageDown: FocusDate(FocusedDate.AddDays(14)); break;
                case Key.Up: FocusDate(FocusedDate.AddDays(-7)); break;
                case Key.Down: FocusDate(FocusedDate.AddDays(7)); break;
                case Key.Left: FocusDate(FocusedDate.AddDays(-1)); break;
                case Key.Right: FocusDate(FocusedDate.AddDays(1)); break;
                case Key.Escape: Hide(); break;
            }
            if (e.Key != Key.Tab) e.Handled = true;
        }

        private void Border_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (e.Delta < 0) FocusDate(FocusedDate.AddDays(7));
            else FocusDate(FocusedDate.AddDays(-7));
            e.Handled = true;
        }

        private void Window_Activated(object sender, EventArgs e)
        {
            if (IsEditing)
            {
                if (toFocus != null)
                {
                    toFocus.Focus();
                    toFocus = null;
                }
                if (editWindow.IsClosed) IsEditing = false;
                else editWindow.Activate();
            }
            else if (IsDeleting)
            {
            }
            else if (InOptions)
            {
                if (optionsWindow.IsClosed) InOptions = false;
                else optionsWindow.Activate();
            }
            else
            {
                if (DateTime.Today < ((CalendarCell)calendarCells.Children[0]).Date ||
                    DateTime.Today > ((CalendarCell)calendarCells.Children[6]).Date)
                    MoveCalendar(DateTime.Today, true);
                if (DateTime.Today != FocusedDate) FocusDate(DateTime.Today);
                if (!IsVisible) Show();
            }
        }

        private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            calendarCells.Focus();
            DragMove();
        }

        private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            calendarCells_KeyDown(sender, e);
        }

        private void settingsImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            settingsImage.Margin = new Thickness(0, 6, 4, 0);
            ShowOptions();
            e.Handled = true;
        }

        private void settingsImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            settingsImage.Margin = new Thickness(0, 5, 5, 0);
        }

        private void settingsImage_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            settingsImage.Margin = new Thickness(0, 5, 5, 0);
        }

        public void ShowOptions()
        {
            if (!InOptions)
            {
                InOptions = true;
                optionsWindow = new Options();
                optionsWindow.Top = Top + 75;
                optionsWindow.Left = Left + 360;
                optionsWindow.Show();
            }
        }
    }
}
